
// Based on
// The Nature of Code
// <http://www.shiffman.net/teaching/nature>
// Spring 2010
// PBox2D example

// An uneven surface boundary
// extended by Florian Weil (www.derhess.de)

class SurfaceComplex implements ISurface{
  // We'll keep track of all of the surface points
  ArrayList<Vec2> surface;
  Body body;

  SurfaceComplex(PVector []  pointlist) {
   
    
    surface = new ArrayList<Vec2>();

    // This is what box2d uses to put the surface in its world
    EdgeChainDef edges = new EdgeChainDef();
   
    float minX =0;
    float minY = 0;
    float maxY = 0;
    float maxX = 0;
    
    // The edgepoints are not in order or in one direction. For this reason the points has to be sorted in a way. 
    ArrayList<PVector> sortedList = sortPoints(pointlist);
    println("StartPoints Surface : " + sortedList.size() + " / " + pointlist.length);
    for (int i = 0; i < sortedList.size(); i++) {
      println(i+ ": points: ("+ sortedList.get(i).x + "/"+ sortedList.get(i).y +")");
    }
    // Edgepoints are too many, so I have to delete the unimportant points...
    LineGeneralization simplify = new LineGeneralization();
    ArrayList<PVector> simpleObjects = simplify.simplifyLang(10f,2f,sortedList);
    println("Simplify Points Surface : " + simpleObjects.size() + " / " + sortedList.size());
    for (PVector p: simpleObjects) {
      println("simplify points: ("+ p.x + "/"+ p.y +")");
    }
    println("Surface End \n");
    
    Vec2 screenEdge;
    Vec2 edge;
    PVector tmp;
    for(int i = simpleObjects.size()-1; i >= 0; i--) {
      tmp = simpleObjects.get(i);
      screenEdge = new Vec2(tmp.x,tmp.y);
      // We store it for rendering
      surface.add(screenEdge);
  
        // Convert it to the box2d world and add it to our EdgeChainDef
      edge = box2d.coordPixelsToWorld(screenEdge);
      edges.addVertex(edge);
    }
 
    
    
    edges.setIsLoop(true);   // We could make the edge a full loop
    edges.friction = 1.0;    // How much friction 2.0
    edges.restitution = 0.5; // How bouncy 0.3

    // The edge chain is now a body!
    BodyDef bd = new BodyDef();
    bd.position.set(0.0f,0.0f);
    body = box2d.world.createBody(bd);
    body.createShape(edges);
    
  }

  // A simple function to just draw the edge chain as a series of vertex points
  void display() {
    strokeWeight(2);
    stroke(0);
    noFill();
    beginShape();
    for (Vec2 v: surface) {
      vertex(v.x,v.y);
    }
    Vec2 tmp = (Vec2)surface.get(0);
    vertex(tmp.x,tmp.y);
    endShape();
  }
  
  void killBody() {
    box2d.destroyBody(body);
  }
  
  ArrayList<PVector> sortPoints(PVector[] source)
  {
     ArrayList<PVector> sortedPointList = new ArrayList<PVector>();
     ArrayList<PVector> sourceList = new ArrayList<PVector>(Arrays.asList(source));
     //print("SortArray");
     int counter = 0;
     int index = 1;
     int maxIterations = 500000;
    
     PVector currPoint = sourceList.get(1);
     PVector oldPoint = sourceList.get(0);
     
     while(sourceList.size() > index && counter < maxIterations) {
       currPoint = sourceList.get(index);
       //check for neighbour
       if(dist(currPoint.x,currPoint.y,oldPoint.x,oldPoint.y) < 3) {
          sortedPointList.add(sourceList.remove(index));
          oldPoint = currPoint;
          //println("neighbour found");
       }
       index++;
       counter++;
       
       //If still points left, continue searching for the next neighbour
       if(sourceList.size() > 0 && index >= sourceList.size()) {
         index = 0;
       }
              
     }
     
     return sortedPointList;
  }

}

